package com.base.component.ai.workflow;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import com.base.component.ai.agent.bo.ContextBO;
import com.base.component.ai.agent.bo.ContextParamBO;
import com.base.component.ai.system.entity.FlowConfigureDO;
import com.base.component.ai.system.entity.FlowRunDO;
import com.base.component.ai.system.service.FlowConfigureService;
import com.base.component.ai.system.service.FlowRunService;
import com.base.component.ai.workflow.core.NodeHandle;
import com.base.component.ai.workflow.core.NodeHandleLog;
import com.base.component.ai.workflow.flow.Flow;
import com.base.component.ai.workflow.node.NodeEnd;
import com.base.component.ai.workflow.result.NodeResultTemplate;
import com.base.component.ai.workflow.utils.FlowUtils;
import com.gitee.magic.context.ConverterEditorUtils;
import com.gitee.magic.core.json.JsonObject;
import com.gitee.magic.framework.base.utils.MapConvert;

@Component
public class FlowEngine<MSG,CP extends ContextParamBO,PP> {
	
	@Autowired
	private List<NodeHandle<MSG,CP,PP>> nodeHandles;
	@Autowired
	private NodeResultTemplate<MSG, CP, PP> resultHandleTemplate;
	@Autowired
	private NodeHandleLog nodeHandleLog;

//	public List<Flow> firstNextFlow(String code) {
//		//TODO:根据code获取对应的json结构生成node
//		String data="""
//				{"nexts":[{"nexts":[{"nexts":[{"node":{"nodeType":"END","params":{}},"name":"end1"}],"node":{"nodeType":"AGENT","beanName":"coreReply","contextParamInjects":["name"],"promptParamInjects":["name"]},"name":"Agent"}],"node":{"expression":{"flowAgentName":[{"node":{"nodeType":"END","params":{"type":"text","value":"值"}},"name":"end"}]},"nodeType":"CONDITION"},"name":"nc"}],"node":{"nodeType":"JDBC_SELECT","valueType":"String","parameterNames":["userId"],"sqlId":"order_id","variableName":"order"},"name":"读取DB"}
//				""";
//		return Arrays.asList(FlowFactory.getFlow(new JsonObject(data)));
//	}
//	
//	/**
//	 * 开始
//	 * @param context
//	 * @param inputs 允许在整个workflow周期内使用的字段
//	 * @param code 通过code获取对应的所有Flow
//	 * @return
//	 */
//	public void start(ContextBO<MSG,CP,PP> context,List<String> inputs,String code) {
//		List<Flow> nextFlows=firstNextFlow(code);
//		start(context,inputs,nextFlows);
//	}
	
	@Autowired
	private FlowConfigureService flowConfigureService;
	@Autowired
	private FlowRunService flowRunService;
	
	public void start(ContextBO<MSG,CP,PP> context,Long flowConfigureId) {
		FlowConfigureDO flowConfigure=flowConfigureService.load(flowConfigureId);
		FlowRunDO flowRun=new FlowRunDO();
		flowRun.setFlowConfigureId(flowConfigureId);
		flowRun.setInputParams(flowConfigure.getInputParams());
		flowRun.setNexts(flowConfigure.getNexts());
		flowRunService.save(flowRun);
		start(flowRun.getId(),context,flowConfigure.getInputParams(),flowConfigure.getNexts());
	}
	
	public void start(Long flowRunId,ContextBO<MSG,CP,PP> context,List<String> inputs,List<Flow> nextFlows) {
		Map<String,Object> msgParams=MapConvert.convert(context.getMsg());
		//初始化可带入的参数
		Map<String,Object> params=new HashMap<>();
		for(String pn:inputs) {
			if(msgParams.containsKey(pn)) {
				params.put(pn, msgParams.get(pn));
			}
		}
		for(Flow nextFlow:nextFlows) {
			execute(flowRunId,context,params,nextFlow);
		}
	}
	
	public void execute(Long flowRunId,ContextBO<MSG,CP,PP> context,Map<String,Object> params,Flow flow) {
		if(flow.getNode().getClass().equals(NodeEnd.class)) {
			Map<String,String> endParams=((NodeEnd)flow.getNode()).getParams();
			Map<String,Object> resultMap=FlowUtils.paramConverMap(params, endParams);
			resultHandleTemplate.execute(context, resultMap);
			return;
		}
		List<Flow> nextFlows=handle(flowRunId,context,params,flow);
		if(CollectionUtils.isEmpty(nextFlows)) {
			return;
		}
		for(Flow nextFlow:nextFlows) {
			execute(flowRunId,context,params,nextFlow);
		}
	}
	
	public List<Flow> handle(Long flowRunId,ContextBO<MSG,CP,PP> context,Map<String,Object> params,Flow flow){
		for(NodeHandle<MSG,CP,PP> handle:nodeHandles) {
			if(handle.support(flow.getNode().getClass())) {
				long startTime=System.currentTimeMillis();
				List<Flow> nexts= handle.execute(context,params,flow,flow.getNode(),(c)->{
					long cost=System.currentTimeMillis()-startTime;
					JsonObject data=ConverterEditorUtils.converter(c, JsonObject.class);
					nodeHandleLog.saveLog(flowRunId,flow.getNode(), data,cost);
				});
				return nexts;
			}
		}
		return flow.getNexts();
	}
	
}
